The purpose of this lab is to:
Before you begin, please create a folder called lab03 inside your cs150 folder (for a refresher, here's how you did this on lab 02). This is where you should put all files made for this lab. You will need the module picture.py so you might as well download it now and save it in your lab03 folder.
You probably remember bumping into that peculiar number Π = 3.14159265..., right? It comes up when you're talking about circles and trigonometry, but also appears in a bunch unexpected places that seem to have little to do with either. As a refresher, Pi can be defined as the ratio of a circle's circumference (Π d) to its diameter (d). One interesting feature of Pi is that it's an irrational number, meaning it cannot be expressed as a fraction m/n where both m and n are integers; consequently, its decimal representation never ends or even repeats.
Since ancient times, mathematicians have been fascinated with the study of Pi and it's various properties. Early approximations of Pi, such as 22/7 and 355/113 were accurate to 3 and 7 digits repsectively (the latter approximation was the best known for nearly a millenium). Currently, more than the first trillion (10^12, or a million million) digits are known. There are many ways to estimate Pi -- for example, you could draw as precise a circle as you can manage, measure its circumference C and diameter d, and then divide C/d; this should give you Pi. Alternatively, there is a geometry-based approach due to Archimedes. We'll investigate a third approach using what is called a Monte Carlo method.
When we say we're using a Monte Carlo method, we usually mean we're going to do a bunch of random trials and observe the fraction of those trials that have a certain property. In our case, we're going to be throwing darts into a square region, and computing the fraction of those darts that land within a circle inscribed inside that square. Each throw is a trial, and the property we are concerned with is whether or not the dart landed inside the circle or not.
Describe the Problem:
Write a program called monte.py that computes an approximate value of Pi.
input: get a number of trials n from the user.
goal: compute and output an approximation to Pi using a Monte Carlo method with n trials.
Understand the Problem:
More precisely, we'll begin by (theoretically) constructing a target circle inscribed in a square. This is our dart board, and the target circle reaches all the way to the edge of the square. It might look something like the following:
Next, we'll simulate repeatedly throwing darts at random against the board above (we'll assume that our random throws alway hits the square, and are equally likely to land at any given point inside the square). We then look at the fraction of the darts that land within the circle out of all those that were thrown. I claim that if we then multiply this fraction by 4, we should have a good approximation to Pi. What sort of dark sorcery is this? Let's take a closer look.
The area of a square is the length of a side squared. Thus our square, with sides of length 2, has an area of 4. The area of a circle is Pi times the radius squared, so for a unit circle (with radius 1), the area is Pi. Therefore, the ratio of the area of our circle to the area of our square is precisely Pi/4. (That is, the circle takes up a Pi/4 portion of our dart board.)
Since each dart lands at a random location in the square, the probability that any one dart lands within the circle should be exactly the fraction of the square taken up by the circle: Pi/4. Thus, if we repeat this experiment over and over again, we'd expect roughly a Pi/4 fraction of the darts to land in the circle. By counting up the fraction that actually land in the circle in our experiments, we've gotten a probabilistic estimate for Pi/4, or a quarter of Pi. If we just multiply that estimate by 4, we've got our approximation for Pi itself. Restating our discussion as a formula, we have
That is, if you throw lots of darts and keep track of the fraction that land inside the circle, multiplying this fraction by 4 should give you an approximate value for Pi. Of course, it is only an approximation: suppose (by some cosmic fluke) that all the darts thrown land near the upper left corner, outside of the circle. Then your approximation for Pi would be 0 (a rather weak estimate). However, as the number of trials increases, the likelihood that your estimate is good increases as well.
A run of the program might appear as follows.
This program calculates the value of Pi by simulating the throwing of darts onto a round target on a square background. How many darts to throw? 1 The value of Pi after 1 iterations is 4.0 which is off by 27.32%
This program calculates the value of Pi by simulating the throwing of darts onto a round target on a square background. How many darts to throw? 100 The value of Pi after 100 iterations is 2.96 which is off by 5.78%
This program calculates the value of Pi by simulating the throwing of darts onto a round target on a square background. How many darts to throw? 1000 The value of Pi after 1000 iterations is 3.084 which is off by 1.83%
Design an Algorithm:
Write pseudocode to approximate Pi via this dart-throwing method--you'll throw random darts at a 2-by-2 board, and calculate what fraction end up within the unit circle. Try this on your own, and then confirm that your pseudocode looks something like the following:
Implement a Design:
Translate your pseudocode into a Python program named monte.py.
In order to implement your pseudocode, you'll need to "throw a dart." Each dart's position is specified by an (x,y) coordinate, so to "throw" a dart, you just need to randomly generate two values for each dart throw (one for x and one for y).
Python has a module that will let you generate random numbers called random. To use it you need to:
import random
rInt = random.randint(0,99)
In general, random.randint(a, b) produces a randon integer between a and b.
rFloat = random.random()
rFloat = random.uniform(a, b)
Now that you have your dart throw, your next question should be: how do I know if I've hit the target? You'll do this by calculating the distance from the center of the circle to the dart and determining if it is within 1 unit and therefore in the circle. If you center the circle at the origin (0,0) and generate x and y values ranging from -1 to 1, you can just use the distance formula to calculate the distance from (x,y) to the origin:
In Python, this formula is math.sqrt(x*x + y*y).You can use the math module to do more advanced arithmetic operations and to give you a decent value of Pi. In particular, math.sqrt(exp) will return the square root of the expression exp, and math.pi is a constant representing the value of Pi. See the online documentation for more details, if you need them. If you use the math module you will need to import this module at the top of your file, using import math.
Conveniently for us, the square root of x*x+y*y is less than or equal to 1 precisely when x*x+y*y <= 1, so taking the square root isn't necessary here. If you are using a large number of iterations, it will speed up your program to not use the square root.
You do not have to calculate the percentage difference between your approximation and Python's math.pi, but it might be interesting to look at.
Test the Program:
Try running your program with an increasing number of trials. Ideally, the more trials you have, the closer to the real value of Pi you get.
You should expect that
each run produces a slightly different value due to the fact that it is
using a random number generator.
Handin:
Just another reminder to run the handin command to hand in your files.
As you may know, a number x is said to be prime if x is at least 2, and the only proper factors of x are itself and 1. So the first few primes are 2, 3, 5, 7, 11, 13, 17, 19, 23, etc. 4 isn't prime, since it is divisible by 2. Same goes for 6 and 8. 9 is out thanks to 3. And so on. There are a lot of primes. More precisely, there are infinitely many primes. This can actually be shown pretty easily; ask if you're curious.
A twin prime is a pair of prime numbers that differ by exactly 2. So (3,5), (5,7), (11,13), (17,19) and (29, 31) are all twin primes. Note that not every prime is part of a twin prime. It is conjectured that there are infinitely many twin primes too, but no one knows for sure.
Describe the Problem:
Write a program called primes.py that prints out some number of primes and the number of twin primes amongst them.
input: get a number n from the user that represents the number of primes to print out.
output: output the first n primes, and the number of twin primes amongst these n.
Understand the Problem:
If the user enters 13 then the output should be
The first 13 primes are: 2 3 5 7 11 13 17 19 23 29 31 37 41 Amongst these there are 5 twin primes.
Note that (41, 43) is a twin prime, but we didn't count it since 43 wasn't amongst the first 13 primes.
Design an Algorithm:
Write pseudocode to solve this problem. You should decompose your main algorithm into small manageable chunks. For example, you should
Implement a Design:
You may want to use a while loop as you search for primes, since you won't know ahead of time just how far you need to go. Ask if you're not sure what a while loop is, or feel free to google it.
Test the Program:
Try your program with a variety of inputs n. Certainly you should try n=0,1,13 but you should also try n=14 to get that one extra twin prime, as well as others!
The last two programs for this lab make use of graphical module that we will also use in several future labs. The standard Python graphical library is very low-level and cumbersome to use, so we will make use of a locally generated module picture.py that is non-standard but much easier to work with. To make use of this module you nwws two things:
make testing easier for now.
We have provided you with a module picture that lets you draw pictures. To use it you need to:
import picture
canvas = picture.Picture(600, 800)This creates a new picture object called canvas which you'll be able to draw upon and display. The parameters specify the width and height of the canvas. Naturally, you can use other values if needed.
canvas.setOutlineColor(r, g, b)
Here r is an expression indicating how much red the pen color should have (from 0 to 255). Similarly, g and b indicate how much green and blue are in the pen color. Some useful (r,g,b) values: (255, 255, 0) is yellow, (0, 0, 0) is black, and (0, 255, 255) is cyan.
The function to set the fill color is what you might expect:
canvas.setFillColor(r, g, b)
You'll also want to use the drawRect and drawRectFill function to draw rectangles and filled rectangles. For example,
canvas.drawRectFill(x, y, w, h)
would draw a filled rectangle in the current pen color. The rectangle would be w pixels wide and h pixels tall. The upper left corner of the rectangle would be located at position (x,y). (Recall that the picture coordinate system, (0,0) is the upper left pixel.)
canvas.display()
import picture2and
canvas = picture2.Picture( 600,600)
Here is a very simple example. This opens a window that is 500 pixels wide and 400 pixels high and draws a red square in the middle of it.
import picture
canvas = picture.Picture(500, 400)
canvas.setFillColor(255,0,0)
canvas.drawRectFill(200,150,100,100)
canvas.display()
Write a program ell.py that inputs a number n and draws an L-shaped figure like this, where the column and row each contain n squares:
This time the squares are a fixed size 100x100, so the canvas is n*100 pixels wide and n*100 pixels high.
Describe the Problem:
You are to input a number n and create a canvas that is (100*n)x(100*n). Draw a column of n 100x100 squares on the left side of the canvas and a row of n 100x100
squares at the bottom of the canvas.
Understand the Problem:
Note that you can't create the canvas until you know the value of n, so you need to do the input first. You can't create a 0x0 canvas, so check for n==0 and exit from the program if it is true. You don't want your program to crash if some smart-alecky professor enters 0 for n. Note also that the drawing canvas changes size for different values of n.
Design an Algorithm:
Here's an algorithm: Draw the column from top to bottom, then draw the row from left to right. To draw each square you need to know the (x,y) coordinates of its top left corner. While it is possible to come up with a formula for these coordinates for the ith square as i counts up from 0, there is a good chance that you will make a mistake in the formula. Here is an easier, almost fool-proof method. Find the (x,y) coordinates of the upper left corner of the first squiare in the column or row; for the column this is (0,0). Then go into a loop that draws n squares with corner (x,y). Each time after yoiu draw a square add whatever you need to x and y to get the corner of the next square.
Implement a Design:
This should be easy to implement. One for-loop draws the column and one draws the row.
Test the program:
You will want to test for the boundary cases n==0 and n==1 as well as for several reasonable values of n. Don't worry about very large values of n for which the canvas doesn't fit on the screen..
Describe the Problem:
Write a program called pyramid.py that draws a pyramid of bricks based on user input.
input: get a numbers width from the user, as well as the number of bricks tall to make the pyramid (n).
goal: draw a pyramid that is n bricks tall in a square canvas width wide (and thus width tall).
Understand the Problem:
Here are three sample outputs for your reference. Notice that the pyramid doesn't necessarily fill the entire canvas to the right and to the top; if the canvas width is not evenly divisible by the number of bricks, then there will be extra blank space. (A question for you to ponder: why is there so much blank space in the third example? Seems like you could fit lots of extra bricks both to the right and up top...)
Design an Algorithm:
Design an Algorithm:
Write pseudocode to draw the appropriate pyramid. The algorithm is
Implement a Design:
Now that you have a detailed algorithm in pseudocode, translate it (bit by bit!) into a Python program named pyramid.py. Although your final program should get the width and number of bricks from the user, you may want to temporarily hard-code this values into your program (using the example values above, perhaps) for now because it will make testing easier for now.
Implementation notes:
Test the Program:
Try running the program with the examples given above as well as some others. Make sure you have gaps where you ought to, and that there aren't gaps where there shouldn't be gaps! Your pyramid should not be sloping to one side or floating in the middle. You shouldn't have some bricks that are larger than others. If it looks fishy, go back and examine your math equations, checking that the "integer division" is being used appropriately.
And don't forget to let the user input the width and number of bricks, if you were testing the program with hard-coded values!
Handin:
Please handin your lab up to this point so that we have some portion of your code submitted.
If you followed the Honor Code in this assignment, make an HonorCode file as you did in Lab 01 with the text:
I affirm that I have adhered to the Honor Code in this assignment.
You now just need to electronically handin all your files. As a reminder
% cd ~ # changes to your home directory % cd cs150 # goes to your cs150 folder % handin # starts the handin program # class is 150 # assignment is 3 # file/directory is lab03 % lshand # should show that you've handed in something
You can also specify the options to handin from the command line
% cd ~/cs150 # goes to your cs150 folder % handin -c 150 -a 3 lab03
monte.py
primes.py
ell.py pyramid.py
picture.py (you should not have modified this; handing it in makes grading easier)
HonorCode (with the Honor Pledge))